package org.jfinanceobserver;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.sql.SQLException;
import java.text.ParseException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import joptsimple.OptionParser;
import joptsimple.OptionSet;
import org.jfinanceobserver.persistence.ConnFactory;
import org.jfinanceobserver.persistence.jpa.controller.QuotesDataJpaController;
import org.jfinanceobserver.persistence.jpa.controller.exceptions.PreexistingEntityException;
import org.jfinanceobserver.persistence.jpa.entities.QuotesActive;
import org.jfinanceobserver.persistence.jpa.entities.QuotesData;
import org.jfinanceobserver.utillities.AbstractDefaultTool;
import org.jfinanceobserver.utillities.CVSParser;
import org.jfinanceobserver.utillities.QuoteProperties;
import org.jfinanceobserver.utillities.QuotesActives;
import org.jfinanceobserver.utillities.Util;

/**
 * This class retrieveAndLoad the quotes into the QuotesData table
 *
 * $Author: r78v10a07@gmail.com $ $LastChangedDate: 2013-02-11 14:03:43 +0100
 * (Mon, 11 Feb 2013) $ $LastChangedRevision: 34 $
 *
 * @since Feb 10, 2013
 */
public class FinanceObserver extends AbstractDefaultTool {

    private QuotesDataJpaController aController = null;

    /**
     * Make a iteration and download the data from the Yahoo finance URL and
     * inserted into the MySQL DBMS
     *
     * @throws IOException
     * @throws PreexistingEntityException
     * @throws Exception
     */
    public void retrieveAndLoad() throws IOException, PreexistingEntityException, Exception {
        try {
            HashMap parm = new HashMap();
            String url = "http://download.finance.yahoo.com/d/quotes.csv?s="
                    + QuotesActives.getInstance().getActivestoString() + "&f=" + QuoteProperties.getInstance().getValues() + "&ignore=.csv";
            URL oracle = new URL(url);
            URLConnection yc = oracle.openConnection();
            try (BufferedReader in = new BufferedReader(new InputStreamReader(yc.getInputStream()))) {
                String inputLine;
                while ((inputLine = in.readLine()) != null) {
                    if (!inputLine.isEmpty()) {
                        String[] val = CVSParser.parse(inputLine);
                        if (val.length == 16) {
                            QuotesActive active = QuotesActives.getInstance().findId(val[14]);
                            if (active != null
                                    && parseString(val[0]) != null
                                    && parseString(val[1]) != null) {
                                QuotesData data = new QuotesData();
                                data.setActiveid(active);

                                if (parseString(val[0]) != null) {
                                    data.setAsk(Float.parseFloat(val[0]));
                                }
                                if (parseString(val[1]) != null) {
                                    data.setBid(Float.parseFloat(val[1]));
                                }
                                if (parseString(val[2]) != null) {
                                    data.setChange1(Float.parseFloat(val[2]));
                                }
                                if (parseString(val[3]) != null) {
                                    data.setChangeInPercent(val[3]);
                                }
                                if (parseString(val[4]) != null) {
                                    data.setChangeRealtime(Float.parseFloat(val[4]));
                                }
                                if (parseString(val[5]) != null) {
                                    data.setCommission(val[5]);
                                }
                                if (parseString(val[6]) != null) {
                                    data.setEbitda(val[6]);
                                }
                                if (parseString(val[7]) != null) {
                                    data.setOneyrTargetPrice(Float.parseFloat(val[7]));
                                }
                                if (parseString(val[8]) != null) {
                                    data.setOpen(Float.parseFloat(val[8]));
                                }
                                if (parseString(val[9]) != null) {
                                    data.setPEGRatio(Float.parseFloat(val[9]));
                                }
                                if (parseString(val[10]) != null) {
                                    data.setPERatio(Float.parseFloat(val[10]));
                                }
                                if (parseString(val[11]) != null) {
                                    data.setPriceBook(Float.parseFloat(val[11]));
                                }
                                if (parseString(val[12]) != null) {
                                    data.setPricePaid(Float.parseFloat(val[12]));
                                }
                                if (parseString(val[13]) != null) {
                                    data.setPriceSales(Float.parseFloat(val[13]));
                                }
                                if (parseString(val[15]) != null) {
                                    data.setVolume(Float.parseFloat(val[15]));
                                }
                                data.setLoadTime(new Date());

                                parm.put("id", active.getId());
                                List<QuotesData> lastData = aController.useNamedQuery("QuotesData.findByActiveId", parm, new int[]{0, 1});
                                if (!lastData.isEmpty()) {
                                    for (QuotesData d : lastData) {
                                        if (!d.equals(data)) {
                                            aController.create(data);
                                        } else {
                                            d.setLoadTime(data.getLoadTime());
                                            aController.edit(d);
                                        }
                                    }
                                }else{
                                   aController.create(data); 
                                }
                            }
                        }
                    }
                }
            }
        } catch (MalformedURLException ex) {
            Logger.getLogger(FinanceObserver.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    private String parseString(String value) {
        if (value.equals("-") || value.equals("N/A")) {
            return null;
        }
        return value;
    }

    /**
     * Run the observer process checking the time. If is between the open time
     * launch the retrieveAndLoad method, otherwise the thread sleep for
     * closeInterval seconds
     *
     * @throws IOException
     * @throws SQLException
     * @throws ParseException
     * @throws PreexistingEntityException
     * @throws Exception
     */
    public void mainIterObserver() throws IOException, SQLException, PreexistingEntityException, Exception {
        int i = 0;
        while (true) {
            Date now = new Date();
            if (now.after(Util.getInstance().openDate()) && now.before(Util.getInstance().closeDate())) {
                i++;
                if (ConnFactory.getInstance().getFactory() == null || !ConnFactory.getInstance().getFactory().isOpen()) {
                    ConnFactory.getInstance().connect();
                    aController = new QuotesDataJpaController(ConnFactory.getInstance().getFactory());
                }
                System.out.println("Iter: " + i + " " + (new Date()).toString());
                retrieveAndLoad();
                try {
                    Thread.sleep(Util.getInstance().openInterval);
                } catch (InterruptedException ex) {
                    Thread.currentThread().interrupt();
                }
            } else {
                if (ConnFactory.getInstance().getFactory() != null && ConnFactory.getInstance().getFactory().isOpen()) {
                    ConnFactory.getInstance().close();
                }
                System.out.println("Market close until: " + Util.getInstance().openDate() + " current time: " + (new Date()).toString());
                try {
                    Thread.sleep(Util.getInstance().closeInterval);
                } catch (InterruptedException ex) {
                    Thread.currentThread().interrupt();
                }
            }
        }
    }

    /**
     * Run the observer process
     *
     * @param args
     * @throws IOException
     * @throws PreexistingEntityException
     * @throws Exception
     */
    public static void main(String[] args) throws IOException, PreexistingEntityException, Exception {
        FinanceObserver inObserver = new FinanceObserver();
        inObserver.parseOptions(args);
        inObserver.mainIterObserver();
    }

    @Override
    protected void parseOptions(String[] args) throws FileNotFoundException {
        OptionParser parser = new OptionParser("o:c:i:s:");
        parser.accepts("o").withRequiredArg().ofType(String.class);
        parser.accepts("c").withRequiredArg().ofType(String.class);
        parser.accepts("i").withRequiredArg().ofType(Long.class);
        parser.accepts("s").withRequiredArg().ofType(Long.class);

        OptionSet options = parseDefaultOptions(parser, args, true);

        Util.getInstance().setOpenHour((String) parseOption(options, "o", "14:00:00", true, false));
        Util.getInstance().setCloseHour((String) parseOption(options, "c", "22:00:00", true, false));
        Util.getInstance().setOpenInterval((Long) parseOption(options, "i", 60000L, true, false));
        Util.getInstance().setCloseInterval((Long) parseOption(options, "s", 60000L, true, false));

    }

    @Override
    protected void printHelp() {
        System.out.println("Arguments:");
        System.out.println("\t-o Open hour (default: 14:00:00)");
        System.out.println("\t-c Close hour (default: 22:00:00)");
        System.out.println("\t-i Open time interval miliseconds (default: 60000)");
        System.out.println("\t-s Close time interval miliseconds (default: 60000)");
        System.out.println("");
        printDefaultHelp();
        System.exit(0);
    }
}
